// Alternate Realms -- Logic Header
// Copyright 2006 Mike Behlen

enum { NOTHING, EXIT, PRINT, SHOWINVENTORY, ENDREAC };
enum { TYPE=ENDREAC+1, ENTER, SAY, TAKE };

class Logic {
public:
  Logic (short, short);
  Logic (short, string, short);
  Logic (short, short, string);
  Logic (short, string, short, string);
  virtual ~Logic () { }

  virtual short getTrigger() { return trigger; }
  virtual short getReaction() { return reaction; }
  virtual string getReactionParameter () { return reactionParameter; }
  virtual string getTriggerParameter () { return triggerParameter; }

protected:
  short trigger;
  string triggerParameter;
  short reaction;
  string reactionParameter;
};

Logic::Logic (short ltrigger, short lreaction) :
  trigger(ltrigger), triggerParameter(""), reaction(lreaction), reactionParameter("")
{ }

Logic::Logic (short ltrigger, string ltriggerParameter, short lreaction) :
  trigger(ltrigger), triggerParameter(ltriggerParameter), reaction(lreaction), reactionParameter("")
{ }

Logic::Logic (short ltrigger, short lreaction, string lreactionParameter) :
  trigger(ltrigger), triggerParameter(""), reaction(lreaction), reactionParameter(lreactionParameter)
{ }

Logic::Logic (short ltrigger, string ltriggerParameter, short lreaction, string lreactionParameter) :
  trigger(ltrigger), triggerParameter(ltriggerParameter), reaction(lreaction), reactionParameter(lreactionParameter)
{ }



// A Plan is a group of Logics
// Basic Plan Node class
class PlanNode {
public:
  PlanNode () {}
  virtual ~PlanNode () {}
  virtual PlanNode * addLogic (Logic *theLogic) = 0;
  virtual const Logic getLogic (short) = 0;
  virtual const Logic getLogic (short, string) = 0;
  virtual const short getReaction (short) = 0;
  virtual const short getReaction (short, string) = 0;
  virtual const string getReactionParameter (short) = 0;
  virtual const string getReactionParameter (short, string) = 0;
};


// Body of the Plan
class PlanBody : public PlanNode {
public:
  PlanBody (Logic *theLogic, PlanNode *theNextNode) { myLogic = theLogic; nextNode = theNextNode; }
  virtual ~PlanBody () { delete nextNode; }
  virtual PlanNode * addLogic (Logic *theLogic);
  virtual const Logic getLogic (short);
  virtual const Logic getLogic (short, string);
  virtual const short getReaction (short);
  virtual const short getReaction (short, string);
  virtual const string getReactionParameter (short);
  virtual const string getReactionParameter (short, string);
private:
  Logic *myLogic;
  PlanNode *nextNode;
};

PlanNode * PlanBody::addLogic (Logic *theLogic) {
  PlanBody *newLogic = new PlanBody (theLogic, this);
  return newLogic;
}

Logic const PlanBody::getLogic (short ltrigger) {
  if (myLogic->getTrigger() == ltrigger)
    return *myLogic;
  return nextNode->getLogic(ltrigger);
}

Logic const PlanBody::getLogic (short ltrigger, string ltriggerParameter) {
  if (myLogic->getTrigger() == ltrigger && myLogic->getTriggerParameter() == ltriggerParameter)
    return *myLogic;
  return nextNode->getLogic(ltrigger, ltriggerParameter);
}

short const PlanBody::getReaction (short ltrigger) {
  if (myLogic->getTrigger() == ltrigger)
    return myLogic->getReaction();
  return nextNode->getReaction(ltrigger);
}

short const PlanBody::getReaction (short ltrigger, string ltriggerParameter) {
  if (myLogic->getTrigger() == ltrigger && myLogic->getTriggerParameter() == ltriggerParameter)
    return myLogic->getReaction(); 
  return nextNode->getReaction(ltrigger, ltriggerParameter);
}

string const PlanBody::getReactionParameter (short ltrigger) {
  if (myLogic->getTrigger() == ltrigger)
    return myLogic->getReactionParameter();
  return nextNode->getReactionParameter(ltrigger);
}

string const PlanBody::getReactionParameter (short ltrigger, string ltriggerParameter) {
  if (myLogic->getTrigger() == ltrigger && myLogic->getTriggerParameter() == ltriggerParameter)
    return myLogic->getReactionParameter();
  return nextNode->getReactionParameter(ltrigger, ltriggerParameter);
}


// Tail of the Plan
class PlanTail : public PlanNode {
public:
  PlanTail () : emptyLogic(NOTHING, NOTHING) { }
  virtual ~PlanTail () { }
  virtual PlanNode * addLogic (Logic *theLogic);
  virtual const Logic getLogic (short) { return emptyLogic; }
  virtual const Logic getLogic (short, string) { return emptyLogic; }
  virtual const short getReaction (short) { return NOTHING; }
  virtual const short getReaction (short, string) { return NOTHING; }
  virtual const string getReactionParameter (short) { return ""; }
  virtual const string getReactionParameter (short, string) { return ""; }
private:
  Logic emptyLogic;
};

PlanNode * PlanTail::addLogic (Logic *theLogic) {
  PlanBody *newLogic = new PlanBody (theLogic, this);
  return newLogic;
}


// Head of the Plan
class PlanHead : public PlanNode {
public:
  PlanHead () { nextNode = new PlanTail; }
  virtual ~PlanHead () { delete nextNode; }
  virtual PlanNode * addLogic (Logic *theLogic) { nextNode = nextNode->addLogic(theLogic); }
  virtual const Logic getLogic (short ltrigger) { 
    return nextNode->getLogic(ltrigger); }
  virtual const Logic getLogic (short ltrigger, string ltriggerParameter) { 
    return nextNode->getLogic(ltrigger, ltriggerParameter); }
  virtual const short getReaction (short ltrigger) { 
    return nextNode->getReaction(ltrigger); }
  virtual const short getReaction (short ltrigger, string ltriggerParameter) { 
    return nextNode->getReaction(ltrigger, ltriggerParameter); }
  virtual const string getReactionParameter (short ltrigger) { 
    return nextNode->getReactionParameter(ltrigger); }
  virtual const string getReactionParameter (short ltrigger, string ltriggerParameter) { 
    return nextNode->getReactionParameter(ltrigger, ltriggerParameter); }
private:
  PlanNode *nextNode;
};


// Plan Class
class Plan {
public:
  Plan () { headNode = new PlanHead; }
  ~Plan () { delete headNode; }
  void addLogic (Logic *theLogic) { headNode->addLogic(theLogic); }
  const Logic getLogic (short ltrigger) { 
    return headNode->getLogic(ltrigger); } 
  const Logic getLogic (short ltrigger, string ltriggerParameter) { 
    return headNode->getLogic(ltrigger, ltriggerParameter); }
  const short getReaction (short ltrigger) { 
    return headNode->getReaction(ltrigger); }
  const short getReaction (short ltrigger, string ltriggerParameter) { 
    return headNode->getReaction(ltrigger, ltriggerParameter); }
  const string getReactionParameter (short ltrigger) { 
    return headNode->getReactionParameter(ltrigger); }
  const string getReactionParameter (short ltrigger, string ltriggerParameter) { 
    return headNode->getReactionParameter(ltrigger, ltriggerParameter); }
private:
  PlanHead *headNode;
};
